#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <termios.h>
#include <ctype.h>
#include <signal.h>

// 串口配置结构体
typedef struct {
    char* name;         // 设备名称
    int fd;             // 文件描述符
    int baud_rate;      // 波特率
    int data_bits;      // 数据位
    int stop_bits;      // 停止位
    char parity;        // 校验位
} Uart_t;

// 全局变量：循环接收标志
volatile int keep_running = 1;

// 信号处理函数：用于处理Ctrl+C中断
void signal_handler(int sig) {
    if (sig == SIGINT) {
        printf("\n接收到中断信号，停止循环接收\n");
        keep_running = 0;
    }
}

// 初始化串口上下文
Uart_t* uart_init_context(const char* name) {
    Uart_t* ctx = (Uart_t*)malloc(sizeof(Uart_t));
    if (!ctx) {
        perror("内存分配失败");
        return NULL;
    }
    memset(ctx, 0, sizeof(Uart_t));
    
    ctx->name = strdup(name);
    if (!ctx->name) {
        free(ctx);
        perror("字符串复制失败");
        return NULL;
    }
    
    ctx->fd = -1;
    ctx->baud_rate = 115200;
    ctx->data_bits = 8;
    ctx->stop_bits = 1;
    ctx->parity = 'N';  // 无校验
    
    return ctx;
}

// 释放串口上下文
void uart_free_context(Uart_t* ctx) {
    if (ctx) {
        if (ctx->name) {
            free(ctx->name);
        }
        if (ctx->fd >= 0) {
            close(ctx->fd);
        }
        free(ctx);
    }
}

// 打开并配置串口
int open_and_configure_uart(Uart_t* ctx) {
    if (!ctx) {
        perror("上下文为空");
        return -1;
    }
    
    // 打开串口设备
    ctx->fd = open(ctx->name, O_RDWR | O_NOCTTY | O_NONBLOCK);
    if (ctx->fd < 0) {
        printf("打开串口 %s 失败: %s\n", ctx->name, strerror(errno));
        return -1;
    }
    
    // 配置串口参数
    struct termios options;
    if (tcgetattr(ctx->fd, &options) != 0) {
        perror("获取串口属性失败");
        close(ctx->fd);
        ctx->fd = -1;
        return -1;
    }
    
    // 清除数据位掩码
    options.c_cflag &= ~CSIZE;
    
    // 设置输入模式（原始模式）
    options.c_lflag &= ~(ICANON | ECHO | ECHOE | ISIG);
    
    // 设置输出模式
    options.c_oflag &= ~OPOST;
    
    // 禁用软件流控制
    options.c_iflag &= ~(IXON | IXOFF | IXANY);
    
    // 设置波特率
    switch (ctx->baud_rate) {
        case 9600:{   cfsetispeed(&options, B9600);   cfsetospeed(&options, B9600);      break;}
        case 38400:{   cfsetispeed(&options, B38400);   cfsetospeed(&options, B38400);   break;}
        case 19200:{   cfsetispeed(&options, B19200);   cfsetospeed(&options, B19200);   break;}
        case 115200:{ cfsetispeed(&options, B115200); cfsetospeed(&options, B115200);    break;}
        case 1000000:{ cfsetispeed(&options, B1000000); cfsetospeed(&options, B1000000);    break;}
        case 1500000:{ cfsetispeed(&options, B1500000); cfsetospeed(&options, B1500000);    break;}
        case 2000000:{ cfsetispeed(&options, B2000000); cfsetospeed(&options, B2000000);    break;}
        case 2500000:{ cfsetispeed(&options, B2500000); cfsetospeed(&options, B2500000);    break;}
        case 3000000:{ cfsetispeed(&options, B3000000); cfsetospeed(&options, B3000000);    break;}
        case 3500000:{ cfsetispeed(&options, B3500000); cfsetospeed(&options, B3500000);    break;}
        case 4000000:{ cfsetispeed(&options, B4000000); cfsetospeed(&options, B4000000);    break;}
        
        default:    { cfsetispeed(&options, B115200); cfsetospeed(&options, B115200);
                     printf("使用默认波特率 115200\n");}
    }
    
    // 设置校验位
    switch (ctx->parity) {
        case 'O':  // 奇校验
            options.c_cflag |= PARENB | PARODD;
            break;
        case 'E':  // 偶校验
            options.c_cflag |= PARENB;
            options.c_cflag &= ~PARODD;
            break;
        case 'N':  // 无校验
        default:
            options.c_cflag &= ~PARENB;
    }
    
    // 设置数据位
    switch (ctx->data_bits) {
        case 7: options.c_cflag |= CS7; break;
        case 8: default: options.c_cflag |= CS8; break;
    }
    
    // 设置停止位
    switch (ctx->stop_bits) {
        case 2: options.c_cflag |= CSTOPB; break;
        case 1: default: options.c_cflag &= ~CSTOPB; break;
    }
    
    // 启用接收和本地模式
    options.c_cflag |= CLOCAL | CREAD;
    
    // 设置超时（0.5秒）和最小接收字符数（0）
    options.c_cc[VTIME] = 5;  // 0.5秒超时
    options.c_cc[VMIN] = 0;   // 不等待字符
    
    // 应用配置
    if (tcsetattr(ctx->fd, TCSANOW, &options) < 0) {
        perror("设置串口属性失败");
        close(ctx->fd);
        ctx->fd = -1;
        return -1;
    }
    
    printf("串口配置成功：%s, 波特率: %d, 数据位: %d, 停止位: %d, 校验: %c\n",
           ctx->name, ctx->baud_rate, ctx->data_bits, ctx->stop_bits, ctx->parity);
    return 0;
}

// 从串口接收数据
int receive_data(Uart_t* ctx, unsigned char* buf, int max_len, int timeout_ms) {
    if (!ctx || ctx->fd < 0 || !buf || max_len <= 0) {
        return -1;
    }
    
    fd_set readfds;
    struct timeval tv;
    
    FD_ZERO(&readfds);
    FD_SET(ctx->fd, &readfds);
    
    // 设置超时
    tv.tv_sec = timeout_ms / 1000;
    tv.tv_usec = (timeout_ms % 1000) * 1000;
    
    int activity = select(ctx->fd + 1, &readfds, NULL, NULL, &tv);
    if (activity < 0) {
        perror("select错误");
        return -1;
    } else if (activity == 0) {
        return 0; // 超时，无数据
    } else {
        int n = read(ctx->fd, buf, max_len);
        if (n > 0) {
            return n;
        } else if (n == 0) {
            return 0; // 无数据
        } else {
            perror("读取数据失败");
            return -1;
        }
    }
}

// 向串口发送数据
int send_data(Uart_t* ctx, unsigned char* data, int len) {
    if (!ctx || ctx->fd < 0 || !data || len <= 0) {
        return -1;
    }
    
    int ret = write(ctx->fd, data, len);
    if (ret != len) {
        printf("发送失败，预期发送 %d 字节，实际发送 %d 字节\n", len, ret);
        return -1;
    }
    return 0;
}

// 辅助函数：将十六进制字符串转换为字节数组
int hex_string_to_bytes(const char* hex_str, unsigned char* bytes, int max_len) {
    int len = strlen(hex_str);
    int byte_count = 0;
    
    if (len % 2 != 0) {
        printf("错误：十六进制字符串长度必须是偶数\n");
        return -1;
    }
    
    for (int i = 0; i < len && byte_count < max_len; i += 2) {
        char hex_pair[3] = {hex_str[i], hex_str[i+1], '\0'};
        char *endptr;
        unsigned long byte = strtoul(hex_pair, &endptr, 16);
        
        if (*endptr != '\0') {
            printf("错误：无效的十六进制字符 '%c' 或 '%c'\n", hex_str[i], hex_str[i+1]);
            return -1;
        }
        
        bytes[byte_count++] = (unsigned char)byte;
    }
    
    return byte_count;
}

// 打印使用方法
void print_usage(const char *program_name) {
    printf("串口通信测试工具\n");
    printf("用法: %s [接收模式] [串口] [波特率] [数据位] [停止位] [校验位] [发送类型:hex/chr] [数据...]\n", program_name);
    printf("\n");
    printf("接收模式:\n");
    printf("  loop     循环接收数据，按Ctrl+C退出\n");
    printf("  single   单次接收数据\n");
    printf("\n");
    printf("选项:\n");
    printf("  -h, --help         显示此帮助信息并退出\n");
    printf("\n");
    printf("参数:\n");
    printf("  串口               串口设备路径，如 /dev/ttyS0 或 /dev/ttyUSB0\n");
    printf("  波特率             串口通信速率，如 9600, 115200 等\n");
    printf("  数据位             数据位长度，通常为 7 或 8\n");
    printf("  停止位             停止位数量，1 或 2\n");
    printf("  校验位             校验方式，N(无), E(偶), O(奇)\n");
    printf("  发送类型           数据发送类型：\n");
    printf("                     hex - 十六进制格式，每个字节用空格分隔\n");
    printf("                     chr - 字符格式，将参数作为字符串发送\n");
    printf("  数据...            根据发送类型提供相应格式的数据\n");
    printf("\n");
    printf("示例:\n");
    printf("  循环接收:   %s loop /dev/ttyS0 115200 8 1 N hex 55 AA 00 01 FF\n", program_name);
    printf("  单次接收:   %s single /dev/ttyUSB0 9600 8 1 E chr Hello World\n", program_name);
    printf("\n");
}

int main(int argc, char *argv[]) {
    // 检查是否请求帮助
    for (int i = 1; i < argc; i++) {
        if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
            print_usage(argv[0]);
            return 0;
        }
    }
    
    // 检查参数数量
    if (argc < 8) {
        printf("错误：参数不足\n");
        print_usage(argv[0]);
        return 1;
    }
    
    // 解析接收模式
    const char* recv_mode = argv[1];
    if (strcmp(recv_mode, "loop") != 0 && strcmp(recv_mode, "single") != 0) {
        printf("错误：无效的接收模式 '%s'，请使用 'loop' 或 'single'\n", recv_mode);
        print_usage(argv[0]);
        return 1;
    }
    
    // 初始化串口上下文
    Uart_t* uart = uart_init_context(argv[2]);
    if (!uart) {
        return 1;
    }
    
    // 解析命令行参数
    uart->baud_rate = atoi(argv[3]);
    uart->data_bits = atoi(argv[4]);
    uart->stop_bits = atoi(argv[5]);
    uart->parity = toupper(argv[6][0]);
    
    const char* data_type = argv[7];
    
    // 打开并配置串口
    if (open_and_configure_uart(uart) < 0) {
        uart_free_context(uart);
        return 1;
    }
    
    printf("串口已打开，接收模式: %s，准备发送数据...\n", recv_mode);
    
    unsigned char send_buf[256] = {0};
    int send_len = 0;
    
    // 处理发送数据
    if (strcmp(data_type, "hex") == 0) {
        // 处理十六进制数据
        for (int i = 8; i < argc; i++) {
            char *endptr;
            unsigned long byte = strtoul(argv[i], &endptr, 16);
            
            if (*endptr != '\0' || byte > 0xFF) {
                printf("错误：无效的十六进制值 '%s'\n", argv[i]);
                uart_free_context(uart);
                return 1;
            }
            
            send_buf[send_len++] = (unsigned char)byte;
        }
        
        printf("发送十六进制数据: ");
        for (int i = 0; i < send_len; i++) {
            printf("%02X ", send_buf[i]);
        }
        printf("\n");
    } 
    else if (strcmp(data_type, "chr") == 0) {
        // 处理字符数据
        if (argc > 8) {
            // 如果有多个参数，将它们连接成一个字符串
            for (int i = 8; i < argc; i++) {
                int len = strlen(argv[i]);
                if (send_len + len >= sizeof(send_buf)) {
                    printf("错误：发送数据过长\n");
                    uart_free_context(uart);
                    return 1;
                }
                memcpy(send_buf + send_len, argv[i], len);
                send_len += len;
                
                // 在参数之间添加空格，除非是最后一个参数
                if (i < argc - 1) {
                    send_buf[send_len++] = ' ';
                }
            }
        } else {
            printf("错误：没有提供字符数据\n");
            uart_free_context(uart);
            return 1;
        }
        
        printf("发送字符数据: %.*s\n", send_len, send_buf);
    } 
    else {
        printf("错误：不支持的发送类型 '%s'，请使用 'hex' 或 'chr'\n", data_type);
        uart_free_context(uart);
        return 1;
    }
    
    // 发送数据
    if (send_data(uart, send_buf, send_len) < 0) {
        printf("数据发送失败\n");
        uart_free_context(uart);
        return 1;
    } else {
        printf("数据发送成功\n");
    }
    
    // 设置信号处理函数，用于循环接收时处理Ctrl+C
    if (strcmp(recv_mode, "loop") == 0) {
        signal(SIGINT, signal_handler);
        printf("按Ctrl+C停止循环接收\n");
    }
    
    // 根据接收模式处理数据接收
    unsigned char recv_buf[256] = {0};
    if (strcmp(recv_mode, "loop") == 0) {
        // 循环接收数据
        while (keep_running) {
            int n = receive_data(uart, recv_buf, sizeof(recv_buf), 1000);  // 1秒超时
            if (n > 0) {
                printf("接收到 %d 字节数据: ", n);
                for (int i = 0; i < n; i++) {
                    printf("%02X ", recv_buf[i]);
                }
                printf("\n");
                
                // 如果接收到的是可打印字符，也以字符串形式显示
                int is_printable = 1;
                for (int i = 0; i < n; i++) {
                    if (!isprint(recv_buf[i])) {
                        is_printable = 0;
                        break;
                    }
                }
                
                if (is_printable) {
                    printf("字符形式: %.*s\n", n, recv_buf);
                }
            }
            // 短暂延时，避免CPU占用过高
            usleep(100000);  // 100ms
        }
    } else {
        // 单次接收数据
        printf("等待接收数据...\n");
        int n = receive_data(uart, recv_buf, sizeof(recv_buf), 2000);  // 2秒超时
        if (n > 0) {
            printf("接收到 %d 字节数据: ", n);
            for (int i = 0; i < n; i++) {
                printf("%02X ", recv_buf[i]);
            }
            printf("\n");
            
            // 如果接收到的是可打印字符，也以字符串形式显示
            int is_printable = 1;
            for (int i = 0; i < n; i++) {
                if (!isprint(recv_buf[i])) {
                    is_printable = 0;
                    break;
                }
            }
            
            if (is_printable) {
                printf("字符形式: %.*s\n", n, recv_buf);
            }
        } else {
            printf("未接收到数据\n");
        }
    }
    
    // 释放资源
    uart_free_context(uart);
    printf("程序结束\n");
    
    return 0;
}